package com.kris;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.ParseException;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.WorkbookUtil;

/**
 * 当月餐补统计表
 *
 * @author zhangqunshi
 */
class MealReport extends Report {

    final String title = "加班餐补统计报表";
    final String[] header = {"姓名", "天数", "餐补"};

    private final List<String> employeeList;
    private final Map<String, EmployeeAttendRecord> records;
    private final String filename;
    private final String sheetName;
    private final List<Date> holidays;
    private final List<Date> excludeHolidays;
    private final BigDecimal moneyPerDay;
    private final String companyBeginTime;
    // 餐补加班时长，单位小时
    private final double mealTimeLevel;

    public MealReport(String excelFileName,
            List<String> employeeList,
            Map<String, EmployeeAttendRecord> records,
            List<Date> holidays,
            List<Date> excludeHolidays,
            BigDecimal moneyPerDay,
            String companyBeginTime,
            double mealTimeLevel) {
        this.filename = excelFileName;
        this.employeeList = employeeList;
        this.records = records;
        this.sheetName = "sheet1";
        this.holidays = holidays;
        this.excludeHolidays = excludeHolidays;
        this.moneyPerDay = moneyPerDay;
        this.companyBeginTime = companyBeginTime;
        this.mealTimeLevel = mealTimeLevel;
    }

    @Override
    public void make() throws FileNotFoundException, IOException, ParseException {
        // 新建一个excel
        Workbook wb = new HSSFWorkbook();

        //工作簿
        String safeName = WorkbookUtil.createSafeSheetName(this.sheetName);
        Sheet sheet = wb.createSheet(safeName);

        // 建立第一个行， 把表的标题放到这里
        Row firstRow = sheet.createRow((short) 0);
        CellStyle titleStyle = wb.createCellStyle();
        titleStyle.setAlignment(HorizontalAlignment.CENTER); // 设置字体居中显示
        titleStyle.setFont(createFontArial18(wb));

        Cell titleCell = firstRow.createCell(0);
        titleCell.setCellValue(title);
        titleCell.setCellStyle(titleStyle);

        // 合并第一行表格
        sheet.addMergedRegion(new CellRangeAddress(
                0, //first row (0-based)
                0, //last row  (0-based)
                0, //first column (0-based)
                2 //last column  (0-based)
        ));

        // 建立表头样式, 设置背景颜色
        CellStyle headerStyle = wb.createCellStyle();
        headerStyle.setFillForegroundColor(IndexedColors.YELLOW.index);
        headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        headerStyle.setAlignment(HorizontalAlignment.CENTER); // 设置字体居中显示
        headerStyle.setFont(createFontArial14(wb));

        // 建立第2行, 设置表头
        Row secondRow = sheet.createRow((short) 1);
        for (int j = 0; j < header.length; j++) {
            Cell headerCell = secondRow.createCell(j);
            headerCell.setCellValue(header[j]);
            headerCell.setCellStyle(headerStyle);
        }

        // ---------------------------------------------
        //                表格数据
        // ---------------------------------------------
        // 表格数据格式
        CellStyle dataStyle = wb.createCellStyle();
        dataStyle.setFont(createFontArial12(wb));

        int rowIndex = 2; //员工数据开始的行数
        // 获取所有员工名单
        // 循环处理每个员工的时间
        for (int i = 0; i < employeeList.size(); i++) {
            String name = employeeList.get(i);

            // 获取一个员工所有的加班信息记录
            EmployeeAttendRecord em = records.get(name);
            if (em == null) {
                // 忽略不存在考勤记录的员工
                continue;
            }

            List<EmployeeWorkTime> worktimes = em.getWorkTimeRecords();
            if (worktimes == null || worktimes.isEmpty()) {
                continue;
            }

            // 此员工加班的天数
            int workOvertimeDays = 0;

            for (int k = 0; k < worktimes.size(); k++) {
                EmployeeWorkTime employeeWorkTime = worktimes.get(k);

                if (DateUtil.isWeekendOrHoliday(employeeWorkTime.getBeginTime(),
                        this.holidays,
                        this.excludeHolidays)) {
                    // 如果是周末和节假日，那么只要呆到12点就有餐补
                    if (stayAfterMoon(employeeWorkTime.getBeginTime(),
                            employeeWorkTime.getEndTime())) {
                        workOvertimeDays++;
                    }
                } else if (hasMeal(
                        employeeWorkTime.getBeginTime(),
                        employeeWorkTime.getEndTime(),
                        this.companyBeginTime,
                        this.mealTimeLevel)) {
                    // 加班时长为0的，不显示到报表中
                    workOvertimeDays++;
                }

            }//end for

            createRow(sheet, rowIndex, name, workOvertimeDays, dataStyle);

            rowIndex++;

        } // end for

        // 设置自动调整列宽度
        sheet.autoSizeColumn(0);
        sheet.autoSizeColumn(1);
        sheet.autoSizeColumn(2);

        FileOutputStream fileOut = new FileOutputStream(this.filename);
        wb.write(fileOut);
        fileOut.close();
    }

    /**
     * 建立报表的一行数据
     *
     * @param sheet
     * @param rowIndex
     * @param employeeName
     * @param days
     * @param dataStyle
     */
    void createRow(Sheet sheet, int rowIndex, String employeeName, int days, CellStyle dataStyle) {
        // 建立一个行
        Row row = sheet.createRow(rowIndex);
        Cell cell0 = row.createCell(0);
        // 员工姓名
        cell0.setCellValue(employeeName);
        cell0.setCellStyle(dataStyle);
        // 员工加班天数
        Cell cell1 = row.createCell(1);
        cell1.setCellValue(days);
        cell1.setCellStyle(dataStyle);
        // 餐补合计
        Cell cell2 = row.createCell(2);
        BigDecimal total = this.moneyPerDay.multiply(new BigDecimal("" + days));
        total.setScale(1, BigDecimal.ROUND_HALF_UP);
        cell2.setCellValue(total.doubleValue());
        cell2.setCellStyle(dataStyle);
    }

    /**
     * 计算是否员工在平时符合餐补标准时间
     *
     * @param beginTime
     * @param endTime
     * @param beginWorkTime
     * @return
     */
    protected boolean hasMeal(Date beginTime, Date endTime,
            String beginWorkTime, double mealTimeLevel) {

        //没有打卡的，都没有餐补
        if (beginTime == null || endTime == null) {
            return false;
        }

        String[] hhmm = beginWorkTime.split(":");
        int hour = Integer.parseInt(hhmm[0]);
        int min = Integer.parseInt(hhmm[1]);

        // 算出公司规定的开始上班时间
        Calendar c = Calendar.getInstance();
        c.setTime(beginTime);
        c.set(Calendar.HOUR_OF_DAY, hour);
        c.set(Calendar.MINUTE, min);
        c.set(Calendar.SECOND, 0);
        Date companyBeginWorkTime = c.getTime();

        // 早于公司规定的时间来上班，不算加班时间
        if (beginTime.before(companyBeginWorkTime)) {
            beginTime = companyBeginWorkTime;
        }

        long diff = endTime.getTime() - beginTime.getTime() - super.NINE_HOUR;
        if (diff < 0) {
            return false;
        }

        double mealTime = mealTimeLevel * super.ONE_HOUR;

        // 如果加班时长大于1.5小时，这认为其加班，并且有餐补
        return diff > mealTime;
    }

    /**
     * 计算员工是否在周末待过中午12点
     *
     * @param beginTime
     * @param endTime
     * @return
     */
    private boolean stayAfterMoon(Date beginTime, Date endTime) {
        //没有打卡的，都没有餐补
        if (beginTime == null || endTime == null) {
            return false;
        }

        Calendar c = Calendar.getInstance();
        c.setTime(beginTime);
        c.set(Calendar.HOUR_OF_DAY, 12);
        c.set(Calendar.MINUTE, 0);
        c.set(Calendar.SECOND, 0);
        Date clock12 = c.getTime();

        return beginTime.before(clock12) && endTime.after(clock12);
    }

}
